import 'dart:math';

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

class ListProviderWidget extends StatefulWidget {
  @override
  _ListProviderWidgetState createState() => _ListProviderWidgetState();
}

class _ListProviderWidgetState extends State<ListProviderWidget> {
  var random = Random();

  void _incrementCounter() {
    var max = 1000000;
    context.read<PersonProvider>().add([Person('${random.nextInt(max)}')]);
  }

  @override
  Widget build(BuildContext context) {
    print('build_ home page');
    var count =
        context.select<PersonProvider, int>((value) => value.items.length);
    return Scaffold(
      appBar: AppBar(
        title: Text('List ChangeNotifierProvider'),
      ),
      body: ListView.builder(
          itemCount: count,
          itemBuilder: (BuildContext context, int index) {
            return _Cell(index);
          }),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}

class _Cell extends StatelessWidget {
  final int index;

  _Cell(this.index);

  @override
  Widget build(BuildContext context) {
    print('build_ cell $index');
    String name = context
        .select<PersonProvider, String>((value) => value.getItem(index)?.name);
    if (name == null) return Container();

    return ListTile(
      title: Text(name),
      onTap: () {
        context
            .read<PersonProvider>()
            .updateName('${Random().nextInt(10000)}', index);
      },
      onLongPress: () => context.read<PersonProvider>().remove(index),
    );
  }
}

class Person {
  String name;
  Person(this.name);

  @override
  int get hashCode => name.hashCode;

  @override
  bool operator ==(Object other) {
    if (other.runtimeType == runtimeType && other is Person) {
      return other.name == name;
    }
    return false;
  }
}

class PersonProvider extends ChangeNotifier {
  PersonProvider() {
    for (var i = 0; i < 3; i++) {
      _items.add(Person('$i'));
    }
  }

  List<Person> _items = [Person('xxx'), Person('yyyy')];

  List<Person> get items => _items;

  void add(List<Person> items) {
    if (items is List && items.isNotEmpty) {
      _items.addAll(items);
      notifyListeners();
    }
  }

  void remove(int index) {
    if (items is List && items.isNotEmpty) {
      _items.removeAt(index);
      notifyListeners();
    }
  }

  void update(Person person, int index) {
    _items[index] = person;

    notifyListeners();
  }

  void updatePerson(Person person, String name) {
    _items.where((element) => element == person).map((e) => e.name = name);

    notifyListeners();
  }

  void updateName(String name, int index) {
    _items[index].name = name;

    notifyListeners();
  }

  Person getItem(int index) {
    if (index < 0 || index >= _items.length) return null;
    return _items[index];
  }
}
